const COREVAR = {
	NWPATH: nw.require('path'),
	NWFS: nw.require('fs'),
	APP_DIR:nw.require('path').dirname(nw.process.execPath),
	PROJECT_DIR: nw.process.cwd(),
	MANIFEST: nw.App.manifest,
	VERSION: nw.App.manifest.version,
	
	
	KEYS: {
		A:65, B:66, C:67, D:68, E:69, F:70, G:71, H:72, I:73, J:74, K:75, L:76,
		M:77,N:78,O:79,P:80,Q:81,R:82,S:83,T:84,U:85,V:86,W:87,X:88,Y:89,Z:90,
		
		NUM0:48, NUM1:49, NUM2:50, NUM3:51, NUM4:52, NUM5:53, NUM6:54, NUM7:55, NUM8:56, NUM9:57,
		SPACE: 32, ENTER: 13, ESC: 27, CTRL:17, SHIFT:16, ALT:18, CAPS_LOCK:20, TAB:9, BREAKSPACE:8, WIN:91, MENU:93,
		RIGHT: 39, DOWN:40, LEFT:37, TOP:38,
		EQUALS:187, HYPHEN:189, SLASH:191, BACKSLASH:220, DOT:190, COMMA:188, SEMICOLON:186, SINGLE_QUOTE:222,
		BRACKETS:219, CLOSE_BRACKETS: 221, SWUNG_DASH:192,
		
		F1: 112, F2: 113, F3: 114, F4: 115, F5: 116, F6: 117, F7: 118, F8: 119, F9: 120, F10: 121, F11: 122, F12: 123,
		INSERT: 45, HOME: 36, PAGE_UP: 33, DELETE: 46, END: 35, PAGE_DOWN:34,
		PRINT_SCREEN: 44, SCROLL_LOCK:145, PAUSE_BREAK: 19,
		NUMPAD0:96, NUMPAD1:97, NUMPAD2:98, NUMPAD3:99, NUMPAD4:100, NUMPAD5:101, NUMPAD6:102, NUMPAD7:103, NUMPAD8:104, NUMPAD9:105,
		NUMPAD_PLUS:107, NUMPAD_MINUS:109, NUMPAD_ASTERISK:106, NUMPAD_SLASH:111, NUMPAD_SWITCH: 144, NUMPAD_DOT: 110
	}
};

(() => {
	window.Core = class Core {
		static isArray(data) {
			return Object.prototype.toString.call(data) == "[object Array]";
		}
		
		static isNumber(data) {
			return Object.prototype.toString.call(data) == "[object Number]";
		}
		
		static isNull(data) {
			return Object.prototype.toString.call(data) == "[object Null]";
		}
		
		static isUndefined(data) {
			return Object.prototype.toString.call(data) == "[object Undefined]";
		}
		
		static isString(data) {
			return Object.prototype.toString.call(data) == "[object String]";
		}

		static isObject(data) {
			return Object.prototype.toString.call(data) == "[object Object]";
		}
		
		static isNull(data) {
			return Object.prototype.toString.call(data) == "[object Null]";
		}
		
		static date(format, time) {
			return _date(format, time);
		}
		
		static get debug() {
			let self = this;
			function gene(name) {
				let nameFunc = name.substr(0,1).toUpperCase() + name.substr(1).replace(/_[a-zA-Z0-9]/g, (row) => {return row.replace('_', '').toUpperCase()});
				
				return `get${nameFunc}(value) { return this.get('${name}', value); }\nset${nameFunc}(value) { return this.set('${name}', value); }\n`;
			}
			
			function genes() {
				let str = '';
				
				for(let i=0; i<arguments.length; i++) {
					str += gene(arguments[i]);
				}
				
				self.copyText(str);
				return str;
			}
			
			return {
				generateFunctions: genes
			}
		}
		
		static setToParentWindow(key, obj) {
			let parent =  window.parent;
			
			while (parent && !parent[key]) {
				parent[key] = obj;
				parent = window.parent;
			}
			
			return this;
		}
		
		static requireJs(paths) {
			paths = paths.split("\n");
			
			for (let i=0; i<paths.length; i++) {
				let path = paths[i];
				path = path.replace(/^\s+/, '').replace(/\s+$/, '');
				
				if(path == '') {
					continue;
				}
				
				if(!_existsResource(path, 'js')) {
					let idName = _pathToIdName(path, 'js');
					document.write(`<script id="${idName}" type="text/javascript" src="${path}"></script>`);
				}
			}
		}
		
		static srcFileExists(path) {
			let file = Core.getSrcFileAbsolutePath(path);
			return nw.require('fs').existsSync(file);
		}
		
		static getSrcFileAbsolutePath(path) {
			return COREVAR.PROJECT_DIR + '/' + path.replace(/^[\\\/]+/, '');
		}
		
		static requireCss(paths) {
			paths = paths.split("\n");
			
			for (let i=0; i<paths.length; i++) {
				let path = paths[i];
				path = path.replace(/^\s+/, '').replace(/\s+$/, '');
				
				if(path[i] == '') {
					continue;
				}
				
				if(!_existsResource(path, 'css')) {
					let idName = _pathToIdName(path, 'css');
					document.write(`<link id="${idName}" rel="stylesheet" href="${path}" />`);
				}
			}
		}
		
		static getSrcContent(file, encoding) {
			encoding = this.isUndefined(encoding) ? 'utf-8' : encoding;
			file = Core.getSrcFileAbsolutePath(file);
			return nw.require('fs').readFileSync(file, encoding);
		}
		
		static requireSrcContent(src, encoding) {
			document.write(this.getSrcContent(src, encoding));
		}
		
		static renderSrcFile(file, data) {
			return layui.laytpl(Core.getSrcContent(file)).render(data);
		}
		
		static copyText(text) {
			nw.Clipboard.get().set(text);
			return text;
		}
		
		static htmlEncode(str) {
			if(!str ||str == '') {
				return '';
			}
		
			return str.replace(/&/g, '&amp;')
				.replace(/"/g, '&quot;')
				.replace(/'/g, '&apos;')
				.replace(/</g, '&lt;')
				.replace(/>/g, '&gt;')
			;
		}
		
		static htmlDecode(str) {
			if(!str || str == '') {
				return '';
			}
			
			return str.replace(/&quot;/g, '"')
				.replace(/&apos;/g, '\'')
				.replace(/&lt;/g, '<')
				.replace(/&gt;/g, '>')
				.replace(/&amp;/g, '&')
			;
		}
		
		static getBaseDir() {
			let fs = nw.require('fs');
			let fileDir = COREVAR.PROJECT_DIR;
			
			if(!fs.existsSync(COREVAR.PROJECT_DIR + '/.dev')) {
				fileDir = COREVAR.APP_DIR;
			}
			
			return fileDir;
		}
	};
	
	function _pathToIdName(path, type) {
		return 'script_' + path.replace(/[\\\/]/g, '_');
	}
	
	function _existsResource(path, type) {
		return !!document.getElementById(_pathToIdName(path, type));
	}
	
	const constDateMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
	const constDateWeekNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
	const constDateDaySuffixs = {1:'st', 2:'nd', 3:'rd', 21:'st', 22:'nd', 23:'rd', 31:'st'};
	const constDateMonthName = ['January', 'February', 'March', 'April', 'May', "Jun", "July", "August", "September", "October", "November", "December"];
	const constDateAmPmName = ['AM', 'PM'];
	
	/**
	 * 时间戳(秒)
	 * @returns {Number}
	 * @private
	 */
	function _time() {return parseInt(_timeMs()/1000);}
	function _timeMs() {return (new Date()).getTime();}
	/**
	 * 作为日期格式转成时间戳(毫秒)
	 * @returns {number}
	 * @private
	 */
	function _toTimestampMs(time) {return (new Date(time.replace(/-/g, '/'))).getTime();}
	
	/**
	 * 作为日期格式转成时间戳(秒)
	 * @returns {Number}
	 * @private
	 */
	function _toTimestamp(time) {return parseInt(_toTimestampMs(time)/1000);}
	
	function _date(format, time) {
		time = time ? time : _time();
		time = Core.isString(time) ? _toTimestamp(time) : time;
		time *= 1000;

		if(!format) {
			format = 'Y-m-d H:i:s';
		} else if(!Core.isString(format)) {
			return null;
		}

		let date = new Date(time);
		let week = date.getDay() == 0 ? 7 : date.getDay();
		let fullYear = date.getFullYear();
		let leepYear = _isLeepYear(fullYear);
		let monthDays = _calcDaysInMonth();
		let daysCountInYear = _calcDaysInYear();
		let weekOfYear = _calcWeekOfYear();

		function _calcDaysInMonth()  {
			let monthDays = constDateMonthDays[date.getMonth()];
			monthDays += (leepYear && date.getMonth() == 1) ? 1 : 0;
			return monthDays;
		}

		function _calcWeekOfYear()
		{
			if(date.getMonth() == 0 && date.getDate() == 0) {
				return 1;
			}

			let firstWeek = (new Date(fullYear + '-01-04')).getDay();
			firstWeek = firstWeek == 0 ? 7 : firstWeek;

			if(daysCountInYear > 4 - firstWeek) {
				// 属于今年的周, 计算当年第一周的范围
				if(daysCountInYear <= 4+(7-firstWeek) && date.getDate() >= 4-(firstWeek-1) && date.getDate() <= 4+(7-firstWeek)) {
					return 1;
				}

				if(date.getMonth() == 11/*12月份末尾需要判断是否是下一年的第一周*/) {
					let nextWeekFirstWeek = (new Date((fullYear+1) + '-01-04')).getDay();
					nextWeekFirstWeek = nextWeekFirstWeek == 0 ? 7 : nextWeekFirstWeek;

					/*计算当天日期是否处于下一年中的第一周范围内*/
					if( date.getDate()-32 >= 4-nextWeekFirstWeek/*下一年的第一周的星期*/) {
						return 1;
					}
				}

				return Math.ceil((daysCountInYear/*当年当前日期的总天数*/ + (7 - week)/*补足日期周数*/ - 3/*4号到当前日的天数*/) / 7);
			} else {
				// 计算去年最后一周
				let lastWeek = (new Date((fullYear-1) + '-12-31')).getDay();
				lastWeek = lastWeek == 0 ? 7 : lastWeek;
				let daysInLastYear = _isLeepYear(fullYear-1) ? 366 : 365;
				return Math.ceil((daysInLastYear/*去年的总天数*/ - 3/*4号到当前日的天数*/ + (7 - lastWeek)/*补足日期周数*/) / 7);
			}
		}

		function _calcDaysInYear()
		{
			let daysCountInYear = 0;

			for(let i=0; i<date.getMonth(); i++) {
				daysCountInYear += constDateMonthDays[i];
			}

			daysCountInYear += (leepYear && date.getMonth() > 1) ? date.getDate()+1 : date.getDate();
			return daysCountInYear;
		}

		function _isLeepYear(y) {
			return (y % 4)==0 && ((y % 100)!=0) || ((y % 400)==0)
		}

		let keymap = {
			d: String(date.getDate()).padStart(2,0), /* 01-31 */
			j: String(date.getDate()), /* 1-31 */
			D: constDateWeekNames[date.getDay()].substr(0, 3),
			l: constDateWeekNames[date.getDay()],
			N: week,
			S: constDateDaySuffixs[date.getDate()]?constDateDaySuffixs[date.getDate()]:'th',
			w: date.getDay(),

			z: daysCountInYear-1, //年份中的第几天 0 - 361
			W: String(weekOfYear).padStart(2,0), //当年第几周

			F: constDateMonthName[date.getMonth()],
			M: constDateMonthName[date.getMonth()].substr(0,3),
			m: String(date.getMonth()+1).padStart(2,0),
			n: date.getMonth() + 1,
			t: monthDays,//指定月份有多少天, 28-31
			L: Number(leepYear), //是否为闰年

			Y: String(fullYear).padStart(0, 4),
			o: fullYear,
			y: String(fullYear).substr(2),

			a: constDateAmPmName[Number(date.getHours() >= 12)].toLowerCase(),
			A: constDateAmPmName[Number(date.getHours() >= 12)].toUpperCase(),
			G: date.getHours(),
			g: date.getHours() == 0 ? 12 : date.getHours()-12,
			H: String(date.getHours()).padStart(2,0),
			h: String(date.getHours() == 0 ? 12 : date.getHours()-12).padStart(2,0),

			i: String(date.getMinutes()).padStart(2,0),
			s: String(date.getSeconds()).padStart(2,0),
			u: String(date.getMilliseconds()).padEnd(6, 0),
			U: parseInt(date.getTime()/1000)
		};

		let newFormat = '';

		for(let i=0; i<format.length; i++) {
			if(Core.isUndefined(keymap[format[i]])) {
				newFormat += format[i];
			} else {
				newFormat += keymap[format[i]];
			}
		}

		return newFormat;
	}
	
	Core.setToParentWindow('Core', Core);
})();